package com.open.capacity.finance.task.gdszcz;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.open.capacity.finance.config.Globals;
import com.open.capacity.finance.entity.SpringScheduledCron;
import com.open.capacity.finance.service.SpringScheduledCronService;
import com.open.capacity.finance.task.ScheduledOfTask;
import com.open.capacity.finance.util.GDSZCZUtils;
import com.open.capacity.reptile.constant.GDSZCZConstant;
import com.open.capacity.reptile.dto.gdszcz.request.CommonRequest;
import com.open.capacity.reptile.dto.gdszcz.response.CommonResponse;
import com.open.capacity.reptile.dto.gdszcz.response.pay.paycard.PayCardData;
import com.open.capacity.reptile.dto.gdszcz.response.pay.payplan.PayPlanData;
import com.open.capacity.reptile.dto.gdszcz.response.pay.payvoucher.PayVoucherData;
import com.open.capacity.reptile.dto.gdszcz.response.pz.glavou.GlaVouDetailData;
import com.open.capacity.reptile.dto.gdszcz.response.pz.glavou.GlaVouHeadData;
import com.open.capacity.reptile.dto.gdszcz.response.pz.glbal.GlBalData;
import com.open.capacity.reptile.dto.gdszcz.response.pz.glvou.GlVouDetailAssData;
import com.open.capacity.reptile.dto.gdszcz.response.pz.glvou.GlVouDetailData;
import com.open.capacity.reptile.dto.gdszcz.response.pz.glvou.GlVouHeadData;
import com.open.capacity.reptile.dto.gdszcz.response.pz.glvou.LpBillVoucherRelData;
import com.open.capacity.reptile.dto.gdszcz.response.pz.ipbiz.LpBizBillAccountedData;
import com.open.capacity.reptile.dto.gdszcz.response.pz.ipbiz.LpBizBillData;
import com.open.capacity.reptile.entity.*;
import com.open.capacity.reptile.service.*;
import com.open.capacity.reptile.util.HttpUtils;
import com.open.capacity.user.model.SysCompany;
import com.open.capacity.user.service.SysConfigService;
import com.open.capacity.utils.DateUtil;
import com.open.capacity.utils.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.Header;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.task.TaskExecutor;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.text.MessageFormat;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;

/**
 * 凭证数据同步
 */
@Component
@Slf4j
public class PzDataTask implements ScheduledOfTask {

    @Autowired
    private TaskExecutor taskExecutor;


    @Autowired
    private GdszczGlaVouHeadService glaVouHeadService;
    @Autowired
    private GdszczGlVouHeadService glVouHeadService;

    @Autowired
    private GdszczGlaVouDetailService glaVouDetailService;
    @Autowired
    private GdszczGlVouDetailService glVouDetailService;

    @Autowired
    private GdszczGlVouDetailAssService glVouDetailAssService;

    @Autowired
    private GdszczLpBizBillService lpBizBillService;

    @Autowired
    private GdszczLpBizBillAccountedService lpBizBillAccountedService;

    @Autowired
    private GdszczGlBalService glBalService;

    @Autowired
    private SpringScheduledCronService cronService;

    @Autowired
    private SysConfigService configService;

    @Autowired
    private GDSZCZUtils gdszczUtils;

    Integer cronId = null;

    @Override
    public void setCronId(Integer cronId) {
        this.cronId = cronId;
    }

    @Override
    public void execute() {
        try {
            log.info("start excute PzDataTask");

            String updateStartTime = "";
            SpringScheduledCron cron = cronService.findById(cronId);
            if (cron != null && cron.getLastExcuteTime() != null) {
                updateStartTime = DateUtil.format(cron.getLastExcuteTime());
            }

            //异步将离线文件写入数据库
            String finalUpdateStartTime = updateStartTime;
            CompletableFuture.runAsync(() -> {
                trigger(finalUpdateStartTime);
            }, taskExecutor);

        } catch (Throwable e) {
            log.error("execute process has error(Throwable) : ", e);
        }
    }

    @Override
    public void trigger(String startTime) {
        String updateStartTime = String.valueOf(DateUtil.parseDate(startTime).getTime() / 1000);
        // 记录开始时间
        long start = System.currentTimeMillis();
        Date now = new Date();
        int currentYear = DateUtil.getYear();
        int fiscalYear = Integer.parseInt(configService.findByKey("gdszcz_fiscalYear").getCnfValue());
        if (StringUtil.isNotEmpty(startTime)) {
            fiscalYear = DateUtil.getYear(DateUtil.parseDate(startTime.substring(0, 10)));
        }

        try {
            Header[] headers = gdszczUtils.packetHeaders();

            String agencyCodeStr = configService.findByKey("gdszcz_agencyCode").getCnfValue();
            String[] agencyCodeArray = agencyCodeStr.split(",");
            for (String agencyCode : agencyCodeArray) {
                Optional<SysCompany> first = Globals.companyList.stream().filter(company -> company.getAgencyCode().equals(agencyCode)).findFirst();
                int startYear = fiscalYear;
                while (startYear <= currentYear) {
                    if (startYear <= 2021) {//不同步2021年前的数据
                        startYear++;
                        continue;
                    }

//                    //1. 凭证主表
                    syncGlVouHead(agencyCode, startYear, updateStartTime, first, headers);

//                    //2. 凭证明细
                    syncGlVouDetail(agencyCode, startYear, updateStartTime, first, headers);
//
//                    //3. 凭证辅助
                    syncGlVouDetailAss(agencyCode, startYear, updateStartTime, first, headers);
//
//                    //4. 单位核算业务单据表未记账
                    syncLpBizBill(agencyCode, startYear, updateStartTime, first, headers);
//
//                    //5. 单位核算业务单据表已记账
                    syncLpBizBillAccounted(agencyCode, startYear, updateStartTime, first, headers);
//
//                    //6. 单位核算期初余额表
                    syncGlBal(agencyCode, startYear, updateStartTime, first, headers);

                    startYear++;
                }
            }

            //更新最后执行成功时间
            cronService.updateExcuteTime(cronId, now, 1, null, (System.currentTimeMillis() - start) / 60000);
        } catch (Exception e) {
            log.error(e.getMessage());
            //更新最后执行失败时间
            cronService.updateExcuteTime(cronId, now, 0, e.getMessage(), (System.currentTimeMillis() - start) / 60000);
        }
    }

    /**
     * gl_vou_head 凭证主表
     */
    private void syncGlVouHead(String agencyCode, Integer fiscalYear, String updateStartTime, Optional<SysCompany> first, Header[] headers) throws IOException {
        CommonRequest request = gdszczUtils.packetRequest(agencyCode, fiscalYear, updateStartTime, "gl_vou_head");
        String responseGlVouHead = HttpUtils.requestForJson(MessageFormat.format(GDSZCZConstant.gl_vou_head_query_url, configService.findByKey("gdszcz_apiurl").getCnfValue()), JSONObject.toJSONString(request), headers);
        CommonResponse<List<GdszczGlVouHead>> responseGlVouHeadData = JSONObject.parseObject(responseGlVouHead, new TypeReference<CommonResponse<List<GdszczGlVouHead>>>() {
        });
        log.info(String.format("gl_vou_head_query_url--请求:agencyCode:{},fiscalYear:{},updateStartTime:{};响应:resultCode：{},resultMessage:{},resultCount:{}"), request.getAgencyCode(), request.getFiscalYear(), request.getUpdateStartTime(), responseGlVouHeadData.getResultCode(), responseGlVouHeadData.getResultMessage(), responseGlVouHeadData.getData().size());
        if (responseGlVouHeadData.getResultCode().equals("000")) {
            for (GdszczGlVouHead s : responseGlVouHeadData.getData()) {
                int existCount = glVouHeadService.exists(s.getVouGuid());
                if (existCount == 0) {
                    if (first.isPresent()) {
                        s.setAgencyCode(first.get().getId());
                    }
                    glVouHeadService.save(s);
                }
            }
        }
    }

    /**
     * gl_vou_detail 凭证分录
     */
    private void syncGlVouDetail(String agencyCode, Integer fiscalYear, String updateStartTime, Optional<SysCompany> first, Header[] headers) throws IOException {
        CommonRequest request = gdszczUtils.packetRequest(agencyCode, fiscalYear, updateStartTime, "gl_vou_detail");
        String responseGlVouDetail = HttpUtils.requestForJson(MessageFormat.format(GDSZCZConstant.gl_vou_detail_query_url, configService.findByKey("gdszcz_apiurl").getCnfValue()), JSONObject.toJSONString(request), headers);


        CommonResponse<List<GdszczGlVouDetail>> responseGlVouDetailData = JSONObject.parseObject(responseGlVouDetail, new TypeReference<CommonResponse<List<GdszczGlVouDetail>>>() {
        });
        log.info(String.format("gl_vou_detail_query_url--请求:agencyCode:{},fiscalYear:{},updateStartTime:{};响应:resultCode：{},resultMessage:{},resultCount:{}"), request.getAgencyCode(), request.getFiscalYear(), request.getUpdateStartTime(), responseGlVouDetailData.getResultCode(), responseGlVouDetailData.getResultMessage(), responseGlVouDetailData.getData().size());
        if (responseGlVouDetailData.getResultCode().equals("000")) {
            for (GdszczGlVouDetail s : responseGlVouDetailData.getData()) {
                int existCount = glVouDetailService.exists(s.getDetailGuid());
                if (existCount == 0) {
                    if (first.isPresent()) {
                        s.setAgencyCode(first.get().getId());
                    }
                    glVouDetailService.save(s);
                }
            }
        }
    }

    /**
     * gl_vou_detail_ass 凭证辅助
     */
    private void syncGlVouDetailAss(String agencyCode, Integer fiscalYear, String updateStartTime, Optional<SysCompany> first, Header[] headers) throws IOException {
        CommonRequest request = gdszczUtils.packetRequest(agencyCode, fiscalYear, updateStartTime, "gl_vou_detail_ass");
        String responseGlVouDetailAss = HttpUtils.requestForJson(MessageFormat.format(GDSZCZConstant.gl_vou_detail_ass_query_url, configService.findByKey("gdszcz_apiurl").getCnfValue()), JSONObject.toJSONString(request), headers);
        CommonResponse<List<GdszczGlVouDetailAss>> responseGlVouDetailAssData = JSONObject.parseObject(responseGlVouDetailAss, new TypeReference<CommonResponse<List<GdszczGlVouDetailAss>>>() {
        });
        log.info(String.format("gl_vou_detail_ass_query_url--请求:agencyCode:{},fiscalYear:{},updateStartTime:{};响应:resultCode：{},resultMessage:{},resultCount:{}"), request.getAgencyCode(), request.getFiscalYear(), request.getUpdateStartTime(), responseGlVouDetailAssData.getResultCode(), responseGlVouDetailAssData.getResultMessage(), responseGlVouDetailAssData.getData().size());
        if (responseGlVouDetailAssData.getResultCode().equals("000")) {
            for (GdszczGlVouDetailAss s : responseGlVouDetailAssData.getData()) {
                int existCount = glVouDetailAssService.exists(s.getDetailAssGuid());
                if (existCount == 0) {
                    if (first.isPresent()) {
                        s.setAgencyCode(first.get().getId());
                    }
                    GdszczGlVouDetail glVouDetail = glVouDetailService.findById(s.getDetailGuid());
                    if (glVouDetail != null) {
                        s.setSetYear(glVouDetail.getSetYear());
                        s.setFisPerd(glVouDetail.getFisPerd());
                        s.setVouDate(glVouDetail.getVouDate());
                        s.setVouDesc(glVouDetail.getVouDesc());
                    }

                    glVouDetailAssService.save(s);
                }
            }
        }
    }

    /**
     * lp_biz_bill 单位核算未记账
     */
    private void syncLpBizBill(String agencyCode, Integer fiscalYear, String updateStartTime, Optional<SysCompany> first, Header[] headers) throws IOException {
        CommonRequest request = gdszczUtils.packetRequest(agencyCode, fiscalYear, updateStartTime, "lp_biz_bill");
        String responseLpBiz = HttpUtils.requestForJson(MessageFormat.format(GDSZCZConstant.lp_biz_bill_query_url, configService.findByKey("gdszcz_apiurl").getCnfValue()), JSONObject.toJSONString(request), headers);
        CommonResponse<List<GdszczLpBizBill>> responseLpBizData = JSONObject.parseObject(responseLpBiz, new TypeReference<CommonResponse<List<GdszczLpBizBill>>>() {
        });
        log.info(String.format("lp_biz_bill_query_url--请求:agencyCode:{},fiscalYear:{},updateStartTime:{};响应:resultCode：{},resultMessage:{},resultCount:{}"), request.getAgencyCode(), request.getFiscalYear(), request.getUpdateStartTime(), responseLpBizData.getResultCode(), responseLpBizData.getResultMessage(), responseLpBizData.getData().size());
        if (responseLpBizData.getResultCode().equals("000")) {
            for (GdszczLpBizBill s : responseLpBizData.getData()) {
                int existCount = lpBizBillService.exists(s.getBillGuid());
                if (existCount == 0) {
                    if (first.isPresent()) {
                        s.setAgencyCode(first.get().getId());
                    }
                    lpBizBillService.save(s);
                }
            }
        }
    }


    /**
     * lp_biz_bill_accounted 凭证主表
     */
    private void syncLpBizBillAccounted(String agencyCode, Integer fiscalYear, String updateStartTime, Optional<SysCompany> first, Header[] headers) throws IOException {
        CommonRequest request = gdszczUtils.packetRequest(agencyCode, fiscalYear, updateStartTime, "lp_biz_bill_accounted");
        String responseLpBizAccounted = HttpUtils.requestForJson(MessageFormat.format(GDSZCZConstant.lp_biz_bill_accounted_query_url, configService.findByKey("gdszcz_apiurl").getCnfValue()), JSONObject.toJSONString(request), headers);
        CommonResponse<List<GdszczLpBizBillAccounted>> responseLpBizAccountedData = JSONObject.parseObject(responseLpBizAccounted, new TypeReference<CommonResponse<List<GdszczLpBizBillAccounted>>>() {
        });
        log.info(String.format("lp_biz_bill_accounted_query_url--请求:agencyCode:{},fiscalYear:{},updateStartTime:{};响应:resultCode：{},resultMessage:{},resultCount:{}"), request.getAgencyCode(), request.getFiscalYear(), request.getUpdateStartTime(), responseLpBizAccountedData.getResultCode(), responseLpBizAccountedData.getResultMessage(), responseLpBizAccountedData.getData().size());
        if (responseLpBizAccountedData.getResultCode().equals("000")) {
            for (GdszczLpBizBillAccounted s : responseLpBizAccountedData.getData()) {
                int existCount = lpBizBillAccountedService.exists(s.getBillGuid());
                if (existCount == 0) {
                    if (first.isPresent()) {
                        s.setAgencyCode(first.get().getId());
                    }
                    lpBizBillAccountedService.save(s);
                }
            }
        }
    }


    /**
     * gl_bal 科目余额表
     */
    private void syncGlBal(String agencyCode, Integer fiscalYear, String updateStartTime, Optional<SysCompany> first, Header[] headers) throws IOException {
        CommonRequest request = gdszczUtils.packetRequest(agencyCode, fiscalYear, updateStartTime, "gl_bal");
        String responseGlBal = HttpUtils.requestForJson(MessageFormat.format(GDSZCZConstant.gl_bal_query_url, configService.findByKey("gdszcz_apiurl").getCnfValue()), JSONObject.toJSONString(request), headers);
        CommonResponse<List<GdszczGlBal>> responseGlBalData = JSONObject.parseObject(responseGlBal, new TypeReference<CommonResponse<List<GdszczGlBal>>>() {
        });

        log.info(String.format("gl_bal_query_url--请求:agencyCode:{},fiscalYear:{},updateStartTime:{};响应:resultCode：{},resultMessage:{},resultCount:{}"), request.getAgencyCode(), request.getFiscalYear(), request.getUpdateStartTime(), responseGlBalData.getResultCode(), responseGlBalData.getResultMessage(), responseGlBalData.getData().size());
        if (responseGlBalData.getResultCode().equals("000")) {
            for (GdszczGlBal s : responseGlBalData.getData()) {
                int existCount = glBalService.exists(s.getBalGuid());
                if (existCount == 0) {
                    if (first.isPresent()) {
                        s.setAgencyCode(first.get().getId());
                    }
                    glBalService.save(s);
                }
            }
        }
    }


}

